<template>
    <!-- #ifndef APP-NVUE -->
    <view :class="['uni-col', sizeClass, pointClassList]" :style="{
        paddingLeft:`${Number(gutter)}rpx`,
        paddingRight:`${Number(gutter)}rpx`,
    }">
        <slot></slot>
    </view>
    <!-- #endif -->
    <!-- #ifdef APP-NVUE -->
    <!-- 在nvue上，类名样式不生效，换为style -->
    <!-- 设置right正值失效，设置 left 负值 -->
    <view :class="['uni-col']" :style="{
        paddingLeft:`${Number(gutter)}rpx`,
        paddingRight:`${Number(gutter)}rpx`,
        width:`${nvueWidth}rpx`,
        position:'relative',
        marginLeft:`${marginLeft}rpx`,
        left:`${right === 0 ? left : -right}rpx`
    }">
        <slot></slot>
    </view>
    <!-- #endif -->
</template>

<script>
    /**
     * Col    布局-列
     * @description    搭配uni-row使用，构建布局。
     * @tutorial    https://ext.dcloud.net.cn/plugin?id=3958
     *
     * @property    {span} type = Number 栅格占据的列数
     *                         默认 24
     * @property    {offset} type = Number 栅格左侧的间隔格数
     * @property    {push} type = Number 栅格向右移动格数
     * @property    {pull} type = Number 栅格向左移动格数
     * @property    {xs} type = [Number, Object] <768px 响应式栅格数或者栅格属性对象
     *                         @description    Number时表示在此屏幕宽度下，栅格占据的列数。Object时可配置多个描述{span: 4, offset: 4}
     * @property    {sm} type = [Number, Object] ≥768px 响应式栅格数或者栅格属性对象
     *                         @description    Number时表示在此屏幕宽度下，栅格占据的列数。Object时可配置多个描述{span: 4, offset: 4}
     * @property    {md} type = [Number, Object] ≥992px 响应式栅格数或者栅格属性对象
     *                         @description    Number时表示在此屏幕宽度下，栅格占据的列数。Object时可配置多个描述{span: 4, offset: 4}
     * @property    {lg} type = [Number, Object] ≥1200px 响应式栅格数或者栅格属性对象
     *                         @description    Number时表示在此屏幕宽度下，栅格占据的列数。Object时可配置多个描述{span: 4, offset: 4}
     * @property    {xl} type = [Number, Object] ≥1920px 响应式栅格数或者栅格属性对象
     *                         @description    Number时表示在此屏幕宽度下，栅格占据的列数。Object时可配置多个描述{span: 4, offset: 4}
     */
    const ComponentClass = 'uni-col';

    // -1 默认值，因为在微信小程序端只给Number会有默认值0
    export default {
        name: 'uniCol',
        // #ifdef MP-WEIXIN
        options: {
            virtualHost: true // 在微信小程序中将组件节点渲染为虚拟节点，更加接近Vue组件的表现
        },
        // #endif
        props: {
            span: {
                type: Number,
                default: 24
            },
            offset: {
                type: Number,
                default: -1
            },
            pull: {
                type: Number,
                default: -1
            },
            push: {
                type: Number,
                default: -1
            },
            xs: [Number, Object],
            sm: [Number, Object],
            md: [Number, Object],
            lg: [Number, Object],
            xl: [Number, Object]
        },
        data() {
            return {
                gutter: 0,
                sizeClass: '',
                parentWidth: 0,
                nvueWidth: 0,
                marginLeft: 0,
                right: 0,
                left: 0
            }
        },
        created() {
            // 字节小程序中，在computed中读取$parent为undefined
            let parent = this.$parent;

            while (parent && parent.$options.componentName !== 'uniRow') {
                parent = parent.$parent;
            }

            this.updateGutter(parent.gutter)
            parent.$watch('gutter', (gutter) => {
                this.updateGutter(gutter)
            })

            // #ifdef APP-NVUE
            this.updateNvueWidth(parent.width)
            parent.$watch('width', (width) => {
                this.updateNvueWidth(width)
            })
            // #endif
        },
        computed: {
            sizeList() {
                let {
                    span,
                    offset,
                    pull,
                    push
                } = this;

                return {
                    span,
                    offset,
                    pull,
                    push
                }
            },
            // #ifndef APP-NVUE
            pointClassList() {
                let classList = [];

                ['xs', 'sm', 'md', 'lg', 'xl'].forEach(point => {
                    const props = this[point];
                    if (typeof props === 'number') {
                        classList.push(`${ComponentClass}-${point}-${props}`)
                    } else if (typeof props === 'object' && props) {
                        Object.keys(props).forEach(pointProp => {
                            classList.push(
                                pointProp === 'span' ?
                                `${ComponentClass}-${point}-${props[pointProp]}` :
                                `${ComponentClass}-${point}-${pointProp}-${props[pointProp]}`
                            )
                        })
                    }
                });

                // 支付宝小程序使用 :class=[ ['a','b'] ]，渲染错误
                return classList.join(' ');
            }
            // #endif
        },
        methods: {
            updateGutter(parentGutter) {
                parentGutter = Number(parentGutter);
                if (!isNaN(parentGutter)) {
                    this.gutter = parentGutter / 2
                }
            },
            // #ifdef APP-NVUE
            updateNvueWidth(width) {
                // 用于在nvue端，span，offset，pull，push的计算
                this.parentWidth = width;
                ['span', 'offset', 'pull', 'push'].forEach(size => {
                    const curSize = this[size];
                    if ((curSize || curSize === 0) && curSize !== -1) {
                        let RPX = 1 / 24 * curSize * width
                        RPX = Number(RPX);
                        switch (size) {
                            case 'span':
                                this.nvueWidth = RPX
                                break;
                            case 'offset':
                                this.marginLeft = RPX
                                break;
                            case 'pull':
                                this.right = RPX
                                break;
                            case 'push':
                                this.left = RPX
                                break;
                        }
                    }
                });
            }
            // #endif
        },
        watch: {
            sizeList: {
                immediate: true,
                handler(newVal) {
                    // #ifndef APP-NVUE
                    let classList = [];
                    for (let size in newVal) {
                        const curSize = newVal[size];
                        if ((curSize || curSize === 0) && curSize !== -1) {
                            classList.push(
                                size === 'span' ?
                                `${ComponentClass}-${curSize}` :
                                `${ComponentClass}-${size}-${curSize}`
                            )
                        }
                    }
                    // 支付宝小程序使用 :class=[ ['a','b'] ]，渲染错误
                    this.sizeClass = classList.join(' ');
                    // #endif
                    // #ifdef APP-NVUE
                    this.updateNvueWidth(this.parentWidth);
                    // #endif
                }
            }
        }
    }
</script>

<style lang='scss' scoped>
    /* breakpoints */
    $--sm: 768px !default;
    $--md: 992px !default;
    $--lg: 1200px !default;
    $--xl: 1920px !default;

    $breakpoints: ('xs' : (max-width: $--sm - 1),
    'sm' : (min-width: $--sm),
    'md' : (min-width: $--md),
    'lg' : (min-width: $--lg),
    'xl' : (min-width: $--xl));

    $layout-namespace: ".uni-";
    $col: $layout-namespace+"col";

    @function getSize($size) {
        @return 1 / 24 * $size * 100 * 1%;
    }

    @mixin res($key, $map:$breakpoints) {
        @if map-has-key($map, $key) {
            @media screen and #{inspect(map-get($map,$key))} {
                @content;
            }
        }

        @else {
            @warn "Undeinfed point: `#{$key}`";
        }
    }

    /* #ifndef APP-NVUE */
    #{$col} {
        float: left;
        box-sizing: border-box;
    }

    #{$col}-0 {
        /* #ifdef APP-NVUE */
        width: 0;
        height: 0;
        margin-top: 0;
        margin-right: 0;
        margin-bottom: 0;
        margin-left: 0;
        /* #endif */
        /* #ifndef APP-NVUE */
        display: none;
        /* #endif */
    }

    @for $i from 0 through 24 {
        #{$col}-#{$i} {
            width: getSize($i);
        }

        #{$col}-offset-#{$i} {
            margin-left: getSize($i);
        }

        #{$col}-pull-#{$i} {
            position: relative;
            right: getSize($i);
        }

        #{$col}-push-#{$i} {
            position: relative;
            left: getSize($i);
        }
    }

    @each $point in map-keys($breakpoints) {
        @include res($point) {
            #{$col}-#{$point}-0 {
                display: none;
            }

            @for $i from 0 through 24 {
                #{$col}-#{$point}-#{$i} {
                    width: getSize($i);
                }

                #{$col}-#{$point}-offset-#{$i} {
                    margin-left: getSize($i);
                }

                #{$col}-#{$point}-pull-#{$i} {
                    position: relative;
                    right: getSize($i);
                }

                #{$col}-#{$point}-push-#{$i} {
                    position: relative;
                    left: getSize($i);
                }
            }
        }
    }

    /* #endif */
</style>
